home *** CD-ROM | disk | FTP | other *** search
/ X User Tools / X User Tools (O'Reilly and Associates)(1994).ISO / sources / xcalc / math.c < prev    next >
C/C++ Source or Header  |  1994-09-27  |  20KB  |  971 lines

  1. /* $XConsortium: math.c,v 1.17 91/07/25 17:51:34 rws Exp $ 
  2.  *
  3.  *  math.c  -  mathematics functions for a hand calculator under X
  4.  *
  5.  *  Author:    John H. Bradley, University of Pennsylvania
  6.  *                (bradley@cis.upenn.edu)
  7.  *                     March, 1987
  8.  *
  9.  *  RPN mode added and port to X11 by Mark Rosenstein, MIT Project Athena
  10.  *
  11.  *  Modified to be a client of the Xt toolkit and the Athena widget set by
  12.  *  Donna Converse, MIT X Consortium.  This is all that remains of the 
  13.  *  original calculator, and it still needs to be rewritten.  The HP
  14.  *  functionality should be separated from the TI functionality. 
  15.  *  Beware the HP functions: there are still errors here.
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <X11/Xos.h>
  20. #include <math.h>
  21. #include <signal.h>
  22. #if !defined(IEEE) && defined(SVR4)
  23. #include <siginfo.h>
  24. #endif
  25. #include <setjmp.h>
  26. #include "xcalc.h"
  27. #include <errno.h>
  28.  
  29. #ifdef _CRAY        /* kludge around Cray STDC compiler */
  30. double (*log_p)() = log;
  31. #define log ((*log_p))
  32. double (*exp_p)() = exp;
  33. #define exp ((*exp_p))
  34. double (*sqrt_p)() = sqrt;
  35. #define sqrt ((*sqrt_p))
  36. double (*log10_p)() = log10;
  37. #define log10 ((*log10_p))
  38. double (*atan2_p)() = atan2;
  39. #define atan2 ((*atan2_p))
  40. double (*asin_p)() = asin;
  41. #define asin ((*asin_p))
  42. double (*acos_p)() = acos;
  43. #define acos ((*acos_p))
  44. double (*atan_p)() = atan;
  45. #define atan ((*atan_p))
  46. double (*sin_p)() = sin;
  47. #define sin ((*sin_p))
  48. double (*cos_p)() = cos;
  49. #define cos ((*cos_p))
  50. double (*tan_p)() = tan;
  51. #define tan ((*tan_p))
  52. double (*pow_p)() = pow;
  53. #define pow ((*pow_p))
  54. #endif /* _CRAY */
  55.  
  56. #ifndef PI        /* sometimes defined in math.h */
  57. #define PI          3.14159265358979
  58. #endif
  59. #define E           2.71828182845904
  60. #define MAXDISP     11
  61. #define DEG 0        /* DRG mode.  used for trig calculations */
  62. #define RAD 1
  63. #define GRAD 2
  64. #define min(a,b) ((a) < (b) ? (a) : (b))
  65. #define max(a,b) ((a) > (b) ? (a) : (b))
  66. #define True    1
  67. #define False   0
  68.  
  69. extern int    errno;
  70. extern int    rpn;
  71. extern char     dispstr[];
  72. extern void draw();
  73. extern void ringbell();
  74. extern void setflag();
  75. extern void Quit();
  76.  
  77. #ifndef IEEE
  78.     jmp_buf env;
  79. #endif
  80.  
  81.  
  82. /* This section is all of the state machine that implements the calculator
  83.  * functions.  Much of it is shared between the infix and rpn modes.
  84.  */
  85.  
  86. int     flagINV, flagPAREN, flagM, drgmode;    /* display flags */
  87.  
  88. static double drg2rad=PI/180.0;  /* Conversion factors for trig funcs */
  89. static double rad2drg=180.0/PI;
  90. static int entered=1;  /* true if display contains a valid number.
  91.                           if==2, then use 'dnum', rather than the string
  92.                           stored in the display.  (for accuracy) 
  93.                           if==3, then error occurred, only CLR & AC work */
  94. /* entered seems to be overloaded - dmc */
  95. static int lift_enabled = 0;    /* for rpn mode only */
  96.  
  97. static int CLR    =0;  /* CLR clears display.  if 1, clears acc, also */
  98. static int OFF    =0;  /* once clears mem, twice quits */
  99. static int Dpoint=0;  /* to prevent using decimal pt twice in a # */
  100. static int clrdisp=1;  /* if true clears display before entering # */
  101. static int accset =0;
  102. static int lastop =kCLR;
  103. static int memop  =kCLR;
  104. static int exponent=0;
  105. static double acc =0.0;
  106. static double dnum=0.0;
  107. #define XCALC_MEMORY 10
  108. static double mem[XCALC_MEMORY] = { 0.0 };
  109.  
  110. /*
  111.  * The following is to deal with the unfortunate assumption that if errno
  112.  * is non-zero then an error has occurred.  On some systems (e.g. Ultrix), 
  113.  * sscanf will call lower level routines that will set errno.
  114.  */
  115.  
  116. void parse_double (src, fmt, dp)
  117.     char *src;
  118.     char *fmt;
  119.     double *dp;
  120. {
  121.     int olderrno = errno;
  122.  
  123.     (void) sscanf (src, fmt, dp);
  124.     errno = olderrno;
  125.     return;
  126. }
  127.  
  128.  
  129. /*********************************/
  130. int pre_op(keynum)
  131.      int keynum;
  132. {
  133.     if (keynum==-1) return(0);
  134.  
  135.     errno = 0;            /* for non-IEEE machines */
  136.  
  137.     if ( (entered==3) && !(keynum==kCLR || keynum==kOFF)) {
  138.       if (rpn) {
  139.     clrdisp++;
  140.       } else {
  141.         ringbell();
  142.         return(1);    /* the intent was probably not to do the operation */
  143.       }
  144.     }
  145.  
  146.     if (keynum != kCLR) CLR=0;
  147.     if (keynum != kOFF) OFF=0;
  148.     return(0);
  149. }
  150.  
  151. #ifndef IEEE
  152.  
  153. /* cannot assign result of setjmp under ANSI C, use global instead */
  154. static int SignalKind;
  155. static int SignalCode;
  156.  
  157. void fail_op()
  158. {
  159.     if (SignalKind == SIGFPE)
  160.     switch (SignalCode) {
  161. #ifdef SVR4
  162.       case FPE_INTDIV:        /* integer divide by zero */
  163.       case FPE_FLTDIV:        /* floating point divide by zero */
  164.     strcpy(dispstr, "divide by 0");
  165.     break;
  166.       case FPE_INTOVF:        /* integer overflow */
  167.       case FPE_FLTOVF:        /* floating point overflow */
  168.     strcpy(dispstr, "overflow");
  169.     break;
  170.       case FPE_FLTUND:        /* floating point underflow */
  171.     strcpy(dispstr, "underflow");
  172.     break;
  173.       case FPE_FLTRES:        /* floating point inexact result */
  174.     strcpy(dispstr, "inexact result");
  175.     break;
  176.       case FPE_FLTINV:        /* invalid floating point operation */
  177.     strcpy(dispstr, "invalid op");
  178.     break;
  179.       case FPE_FLTSUB:        /* subscript out of range */
  180.     strcpy(dispstr, "out of range");
  181.     break;
  182.  
  183. #endif /*SVR4*/
  184.  
  185. #ifdef FPE_FLTDIV_TRAP
  186.       case FPE_FLTDIV_TRAP:  strcpy(dispstr,"div by zero"); break;
  187. #endif
  188. #ifdef FPE_FLTDIV_FAULT
  189.            case FPE_FLTDIV_FAULT: strcpy(dispstr,"div by zero"); break;
  190. #endif
  191. #ifdef FPE_FLTOVF_TRAP
  192.            case FPE_FLTOVF_TRAP:  strcpy(dispstr,"overflow"); break;
  193. #endif
  194. #ifdef FPE_FLTOVF_FAULT
  195.            case FPE_FLTOVF_FAULT: strcpy(dispstr,"overflow"); break;
  196. #endif
  197. #ifdef FPE_FLTUND_TRAP
  198.            case FPE_FLTUND_TRAP:  strcpy(dispstr,"underflow"); break;
  199. #endif
  200. #ifdef FPE_FLTUND_FAULT
  201.            case FPE_FLTUND_FAULT: strcpy(dispstr,"underflow"); break;
  202. #endif
  203.            default:               strcpy(dispstr,"error");
  204.     }
  205.     else 
  206.     if (SignalKind == SIGILL)
  207.         strcpy(dispstr, "illegal operand");
  208.  
  209.     entered=3;
  210.     DrawDisplay();
  211.     return;
  212. }
  213.  
  214.  
  215. /* keep SVR4 compiler from complaining about scope of arg declaration below */
  216. typedef struct sigcontext * sigcontextstructp;
  217. /*ARGSUSED*/
  218. signal_t fperr(sig,code,scp)
  219.   int sig,code;
  220.   sigcontextstructp scp;
  221. {
  222. #ifdef SYSV
  223.     signal(SIGFPE,(signal_t (*)())fperr);
  224. #endif
  225.     SignalKind = sig;
  226.     SignalCode = code;
  227.     longjmp(env,1);
  228. }
  229.  
  230. /* for VAX BSD4.3 */
  231. /*ARGSUSED*/
  232. signal_t illerr(sig,code,scp)
  233.   int sig,code;
  234.   sigcontextstructp scp;
  235. {
  236.     /* not reset when caught? */
  237.     signal(SIGILL,(signal_t (*)())illerr);
  238.  
  239.     SignalKind = sig;
  240.     SignalCode = code;
  241.     longjmp(env,1);
  242. }
  243.  
  244. #endif    /* not IEEE */
  245.  
  246.  
  247. void post_op()
  248. {
  249. #ifdef DEBUG
  250.     showstack("\0");
  251. #endif
  252. #ifndef IEEE
  253.     if (errno) {
  254.         strcpy(dispstr,"error");
  255.         DrawDisplay();
  256.         entered=3;
  257.         errno=0;
  258.         }
  259. #endif
  260. }
  261. /*-------------------------------------------------------------------------*/
  262. DrawDisplay()
  263. {
  264.     if ((int) strlen(dispstr) > 12) {     /* strip out some decimal digits */
  265.         char tmp[32];
  266.         char *estr = index(dispstr,'e');  /* search for exponent part */
  267.         if (!estr) dispstr[12]='\0';      /* no exp, just trunc. */
  268.         else {
  269.             if ((int) strlen(estr) <= 4) 
  270.                 sprintf(tmp,"%.8s",dispstr); /* leftmost 8 chars */
  271.             else
  272.                 sprintf(tmp,"%.7s",dispstr); /* leftmost 7 chars */
  273.             strcat (tmp,estr);            /* plus exponent */
  274.             strcpy (dispstr,tmp);
  275.             }
  276.         }
  277.     draw(dispstr);
  278.     setflag(XCalc_MEMORY, (flagM));
  279.     setflag(XCalc_INVERSE, (flagINV));
  280.     setflag(XCalc_DEGREE, (drgmode==DEG));
  281.     setflag(XCalc_RADIAN, (drgmode==RAD));
  282.     setflag(XCalc_GRADAM, (drgmode==GRAD));
  283.     setflag(XCalc_PAREN, (flagPAREN));
  284. }
  285.  
  286. /*-------------------------------------------------------------------------*/
  287. numeric(keynum)
  288.      int keynum;
  289. {
  290.     char    st[2];
  291.     int        cell;
  292.  
  293.   flagINV=0;
  294.  
  295.   if (rpn && (memop == kSTO || memop == kRCL || memop == kSUM)) {
  296.       switch (keynum) {
  297.     case kONE:    cell = 1; break;
  298.     case kTWO:    cell = 2; break;
  299.     case kTHREE:    cell = 3; break;
  300.     case kFOUR:    cell = 4; break;
  301.     case kFIVE:    cell = 5; break;
  302.     case kSIX:    cell = 6; break;
  303.     case kSEVEN:    cell = 7; break;
  304.     case kEIGHT:    cell = 8; break;
  305.     case kNINE:    cell = 9; break;
  306.     case kZERO:    cell = 0; break;
  307.       }
  308.       switch (memop) {
  309.       case kSTO:
  310.     mem[cell] = dnum;
  311.     lift_enabled = 1;
  312.       entered = 2;
  313.       clrdisp++;
  314.     break;
  315.       case kRCL:
  316.     PushNum(dnum);
  317.     dnum = mem[cell];
  318.     sprintf(dispstr, "%.8g", dnum);
  319.     lift_enabled = 1;
  320.         entered = 1;
  321.     clrdisp = 0;
  322.     break;
  323.       case kSUM:
  324.     mem[cell] += dnum;
  325.     lift_enabled = 1;
  326.       entered = 2;
  327.       clrdisp++;
  328.     break;
  329.       }
  330.       memop = kCLR;
  331.       DrawDisplay();
  332.       return;
  333.   }
  334.  
  335.   if (clrdisp) {
  336.     dispstr[0]='\0';
  337.     exponent=Dpoint=0;
  338. /*    if (rpn && entered==2)
  339.       PushNum(dnum);
  340.  */
  341.     if (rpn & lift_enabled)
  342.     PushNum(dnum);
  343.   }
  344.   if ((int) strlen(dispstr) >= MAXDISP)
  345.     return;
  346.     
  347.     switch (keynum){
  348.       case kONE:    st[0] = '1'; break;
  349.       case kTWO:    st[0] = '2'; break;
  350.       case kTHREE:    st[0] = '3'; break;
  351.       case kFOUR:    st[0] = '4'; break;
  352.       case kFIVE:    st[0] = '5'; break;
  353.       case kSIX:    st[0] = '6'; break;
  354.       case kSEVEN:    st[0] = '7'; break;
  355.       case kEIGHT:    st[0] = '8'; break;
  356.       case kNINE:    st[0] = '9'; break;
  357.       case kZERO:    st[0] = '0'; break;
  358.     }
  359.     st[1] = '\0';
  360.     strcat(dispstr,st);
  361.  
  362.   DrawDisplay();
  363.   if (clrdisp && keynum != kZERO)
  364.     clrdisp=0; /*no leading 0s*/
  365.   entered=1;
  366.   lift_enabled = 0;
  367. }
  368.  
  369. bkspf()
  370. {
  371.  
  372.   lift_enabled = 0;
  373.  
  374.   if (! flagINV)
  375.   {
  376.       if (entered!=1 || clrdisp)
  377.       return;
  378.       if ((int) strlen(dispstr) > 0)
  379.       dispstr[strlen(dispstr)-1] = 0;
  380.       if (strlen(dispstr) == 0) {
  381.       strcat(dispstr, "0");
  382.       clrdisp++;
  383.       }
  384.   }
  385.   else
  386.   {
  387.       strcpy(dispstr, "0");
  388.       dnum = 0.0;
  389.       clrdisp++;
  390.       flagINV = 0;
  391.   }
  392.   DrawDisplay();
  393. }
  394.  
  395. decf()
  396. {
  397.   flagINV=0;
  398.   if (clrdisp) {
  399.       if (rpn)
  400.     PushNum(dnum);
  401.       strcpy(dispstr,"0");
  402.   }
  403.   if (!Dpoint) {
  404.     strcat(dispstr,".");
  405.     DrawDisplay();
  406.     Dpoint++;
  407.   }
  408.   clrdisp=0;
  409.   entered=1;
  410. }
  411.  
  412. eef()
  413. {
  414.   flagINV=0;
  415.   if (clrdisp) {
  416.       if (rpn && lift_enabled)
  417.     PushNum(dnum);
  418.       strcpy(dispstr, rpn ? "1" : "0");
  419.   }
  420.   if (!exponent) {
  421.     strcat(dispstr,"E+");
  422.     DrawDisplay();
  423.     exponent=strlen(dispstr)-1;  /* where the '-' goes */
  424.   }
  425.   clrdisp=0;
  426.   entered=1;
  427. }
  428.  
  429. clearf()
  430. {
  431.   flagINV=0;
  432.   if (CLR && !rpn) { /* clear all */
  433.     ClearStacks();
  434.     flagPAREN=0;
  435.   }
  436.   CLR++;
  437.   exponent=Dpoint=0;
  438.   clrdisp=1;
  439.   entered=1;
  440.   strcpy(dispstr,"0");
  441.   DrawDisplay();
  442. }
  443.  
  444. negf()
  445. {
  446.   flagINV=0;
  447.   if (exponent) {       /* neg the exponent */
  448.     if (dispstr[exponent]=='-')
  449.       dispstr[exponent]='+';
  450.     else
  451.       dispstr[exponent]='-';
  452.     DrawDisplay();
  453.     return;
  454.   }
  455.  
  456.   if (strcmp("0",dispstr)==0)
  457.     return;            /* don't neg a zero */
  458.   if (dispstr[0]=='-')         /* already neg-ed */
  459.     strcpy(dispstr,dispstr+1);  /* move str left once */
  460.   else {            /* not neg-ed.  add a '-' */
  461.     char tmp[32];
  462.     sprintf(tmp,"-%s",dispstr);
  463.     strcpy(dispstr,tmp);
  464.   }
  465.   if (entered==2)
  466.     dnum = -1.0 * dnum;
  467.   DrawDisplay();
  468. }
  469.  
  470. /* Two operand functions for infix calc */
  471. twoop(keynum)
  472. {
  473.   double PopNum();
  474.  
  475.   if (flagINV) {
  476.     flagINV=0;
  477.     DrawDisplay();
  478.   }
  479.  
  480.   if (!entered) {        /* something like "5+*" */
  481.     if (!isopempty())
  482.       (void) PopOp();            /* replace the prev op */
  483.     PushOp(keynum);        /* with the new one */
  484.     return;
  485.   }
  486.   
  487.   if (entered==1)
  488.     parse_double(dispstr,"%lf",&dnum);
  489.  
  490.   clrdisp=CLR=1;
  491.   entered=Dpoint=exponent=0;
  492.  
  493.   if (!isopempty()) {  /* there was a previous op */
  494.     lastop=PopOp();   /* get it */
  495.  
  496.     if (lastop==kLPAR) {  /* put it back */
  497.       PushOp(kLPAR);
  498.       PushOp(keynum);
  499.       PushNum(dnum);
  500.       return;
  501.     }
  502.  
  503.     /* now, if the current op (keynum) is of
  504.        higher priority than the lastop, the current
  505.        op and number are just pushed on top 
  506.        Priorities:  (Y^X) > *,/ > +,- */
  507.     
  508.     if (priority(keynum) > priority(lastop)) {
  509.       PushNum(dnum);
  510.       PushOp(lastop);
  511.       PushOp(keynum);
  512.     } else {  /* execute lastop on lastnum and dnum, push
  513.            result and current op on stack */
  514.       acc=PopNum();
  515.       switch (lastop) { /* perform the operation */
  516.       case kADD: acc += dnum;  break;
  517.       case kSUB: acc -= dnum;  break;
  518.       case kMUL: acc *= dnum;  break;
  519.       case kDIV: acc /= dnum;  break;
  520.       case kPOW: acc =  pow(acc,dnum);  break;
  521.     }
  522.       PushNum(acc);
  523.       PushOp(keynum);
  524.       sprintf(dispstr,"%.8g",acc);
  525.       DrawDisplay();
  526.       dnum=acc;
  527.     }
  528.   }
  529.   else { /* op stack is empty, push op and num */
  530.     PushOp(keynum);
  531.     PushNum(dnum);
  532.   } 
  533. }                      
  534.  
  535. /* Two operand functions for rpn calc */
  536. twof(keynum)
  537. {
  538.   double PopNum();
  539.  
  540.   if (flagINV) {
  541.     flagINV=0;
  542.     DrawDisplay();
  543.   }
  544.   if (!entered)
  545.     return;
  546.   if (entered==1)
  547.     parse_double(dispstr, "%lf", &dnum);
  548.   acc = PopNum();
  549.   switch(keynum) {
  550.   case kADD: acc += dnum;  break;
  551.   case kSUB: acc -= dnum;  break;
  552.   case kMUL: acc *= dnum;  break;
  553.   case kDIV: acc /= dnum;  break;
  554.   case kPOW: acc =  pow(acc,dnum);  break;
  555.   case kXXY: PushNum(dnum);
  556.   }
  557.   sprintf(dispstr, "%.8g", acc);
  558.   DrawDisplay();
  559.   clrdisp++;
  560.   Dpoint = exponent = 0;
  561.   entered = 2;
  562.   lift_enabled = 1;
  563.   dnum = acc;
  564. }
  565.  
  566.  
  567. entrf()
  568. {
  569.   flagINV=0;
  570.   if (!entered)
  571.     return;
  572.  
  573.   clrdisp=CLR=1;
  574.   Dpoint=exponent=0;
  575.  
  576.   if (entered==1)
  577.     parse_double(dispstr,"%lf",&dnum);
  578.   entered=2;
  579.   memop = kENTR;
  580.   PushNum(dnum);
  581.   lift_enabled = 0;
  582. }
  583.  
  584. equf()
  585. {
  586.   double PopNum();
  587.  
  588.   flagINV=0;
  589.   if (!entered)
  590.     return;
  591.  
  592.   clrdisp=CLR=1;
  593.   Dpoint=exponent=0;
  594.  
  595.   if (entered==1)
  596.     parse_double(dispstr,"%lf",&dnum);
  597.   entered=2;
  598.  
  599.   PushNum(dnum);
  600.  
  601.   while (!isopempty()) {  /* do all pending ops */
  602.     dnum=PopNum();
  603.     acc=PopNum();
  604.     lastop=PopOp();
  605.     switch (lastop) {
  606.     case kADD:  acc += dnum;
  607.         break;
  608.     case kSUB:  acc -= dnum;
  609.         break;
  610.     case kMUL:  acc *= dnum;
  611.         break;
  612.     case kDIV:  acc /= dnum;
  613.         break;
  614.     case kPOW:  acc = pow(acc,dnum);
  615.         break;
  616.     case kLPAR:    flagPAREN--;
  617.         PushNum(acc);
  618.         break;
  619.     }
  620.     dnum=acc;
  621.     PushNum(dnum);
  622.   }
  623.  
  624.   sprintf(dispstr,"%.8g",dnum);
  625.   DrawDisplay();
  626. }
  627.         
  628. lparf()
  629. {
  630.   flagINV=0;
  631.   PushOp(kLPAR);
  632.   flagPAREN++;
  633.   DrawDisplay();
  634. }
  635.  
  636. rollf()
  637. {
  638.   double PopNum();
  639.  
  640.   if (!entered)
  641.     return;
  642.   if (entered==1)
  643.     parse_double(dispstr, "%lf", &dnum);
  644.   entered = 2;
  645.   lift_enabled = 1;
  646.   RollNum(flagINV);
  647.   flagINV=0;
  648.   clrdisp++;
  649.   sprintf(dispstr, "%.8g", dnum);
  650.   DrawDisplay();
  651. }
  652.  
  653. rparf()
  654. {
  655.   double PopNum();
  656.  
  657.   flagINV=0;
  658.   if (!entered)
  659.     return;
  660.  
  661.   if (!flagPAREN)
  662.     return;
  663.   
  664.   clrdisp++;
  665.   Dpoint=exponent=0;
  666.  
  667.   if (entered==1)
  668.     parse_double(dispstr,"%lf",&dnum);
  669.   entered=2;
  670.  
  671.   PushNum(dnum);
  672.   while (!isopempty() && (lastop=PopOp())!=kLPAR) {
  673.     /* do all pending ops, back to left paren */
  674.     dnum=PopNum();
  675.     acc=PopNum();
  676.     switch (lastop) {
  677.     case kADD:  acc += dnum;
  678.         break;
  679.     case kSUB:  acc -= dnum;
  680.         break;
  681.     case kMUL:  acc *= dnum;
  682.         break;
  683.     case kDIV:  acc /= dnum;
  684.         break;
  685.     case kPOW:  acc = pow(acc,dnum);
  686.         break;
  687.     }
  688.     dnum=acc;
  689.     PushNum(dnum);
  690.   }
  691.   (void) PopNum();
  692.   flagPAREN--;
  693.   entered=2;
  694.   sprintf(dispstr,"%.8g",dnum);
  695.   DrawDisplay();
  696. }
  697.  
  698. drgf()
  699. {
  700.   if (flagINV) {
  701.     if (entered==1)
  702.       parse_double(dispstr,"%lf",&dnum);
  703.     switch (drgmode) {
  704.     case DEG:  dnum=dnum*PI/180.0;    break;
  705.     case RAD:  dnum=dnum*200.0/PI;    break;
  706.     case GRAD: dnum=dnum*90.0/100.0;  break;
  707.     }
  708.     entered=2;
  709.     clrdisp=1;
  710.     flagINV=0;
  711.     sprintf(dispstr,"%.8g",dnum);
  712.   }
  713.                          
  714.   flagINV=0;
  715.   drgmode = (drgmode + 1) % 3;
  716.   switch (drgmode) {
  717.   case DEG:  drg2rad=PI / 180.0;
  718.          rad2drg=180.0 / PI;
  719.          break;
  720.   case RAD:  drg2rad=1.0;
  721.          rad2drg=1.0;
  722.          break;
  723.   case GRAD: drg2rad=PI / 200.0;
  724.          rad2drg=200.0 / PI;
  725.          break;
  726.   }
  727.   DrawDisplay();
  728. }
  729.  
  730. invf()
  731. {
  732.   flagINV = ~flagINV;
  733.   DrawDisplay();
  734. }
  735.  
  736. memf(keynum)
  737. {
  738.     memop = keynum;
  739.     if (entered==1)
  740.       parse_double(dispstr,"%lf",&dnum);
  741.     entered = 2;
  742.     clrdisp++;
  743.     lift_enabled = 0;
  744. }
  745.  
  746. oneop(keynum)
  747. {
  748.   int i,j;
  749.   double dtmp;
  750.  
  751.   if (entered==1)
  752.     parse_double(dispstr,"%lf",&dnum);
  753.   entered = 2;
  754.  
  755.   switch (keynum) {  /* do the actual math fn. */
  756.   case kE:     if (rpn && memop != kENTR) PushNum(dnum); dnum=E;  break;
  757.   case kPI:    if (rpn && memop != kENTR) PushNum(dnum); dnum=PI;  break;
  758.   case kRECIP: dnum=1.0/dnum;  break;
  759.   case kSQR:   flagINV = !flagINV; /* fall through to */
  760.   case kSQRT:  if (flagINV) dnum=dnum*dnum;
  761.            else dnum=sqrt(dnum);
  762.            break;
  763.   case k10X:   flagINV = !flagINV; /* fall through to */
  764.   case kLOG:   if (flagINV) dnum=pow(10.0,dnum);
  765.              else dnum=log10(dnum);
  766.            break;
  767.   case kEXP:   flagINV = !flagINV; /* fall through to */
  768.   case kLN:    if (flagINV) dnum=exp(dnum);
  769.            else dnum=log(dnum);
  770.            break;
  771.   case kSIN:   if (flagINV) dnum=asin(dnum)*rad2drg;
  772.            else dnum=sin(dnum*drg2rad);
  773.            break;
  774.   case kCOS:   if (flagINV) dnum=acos(dnum)*rad2drg;
  775.            else dnum=cos(dnum*drg2rad);
  776.            break;
  777.   case kTAN:   if (flagINV) dnum=atan(dnum)*rad2drg;
  778.            else dnum=tan(dnum*drg2rad);
  779.            break;
  780.   case kSTO:   mem[0]=dnum;  flagM=!(mem[0]==0.0);  break;
  781.   case kRCL:   if (rpn && lift_enabled) PushNum(dnum);
  782.                dnum=mem[0];  flagM=!(mem[0]==0.0);  break;
  783.   case kSUM:   mem[0]+=dnum; flagM=!(mem[0]==0.0);  break;
  784.   case kEXC:   dtmp=dnum; dnum=mem[0];  mem[0]=dtmp;
  785.            flagM=!(mem[0]==0.0);  break;
  786.   case kFACT:  if (floor(dnum)!=dnum || dnum<0.0 || dnum>500.0) {
  787.          strcpy(dispstr,"error");
  788.          entered=3;
  789.          break;
  790.            }
  791.            i=(int) (floor(dnum));
  792.            for (j=1,dnum=1.0; j<=i; j++) 
  793.          dnum*=(float) j;
  794.            break;
  795.   }
  796.   
  797.   if (entered==3) {  /* error */
  798.     DrawDisplay();
  799.     return;
  800.   }
  801.  
  802.   entered=2;
  803.   clrdisp=1;
  804.   flagINV=0;
  805.   lift_enabled = 1;
  806.   sprintf(dispstr,"%.8g",dnum);
  807.   DrawDisplay();
  808. }
  809.  
  810. offf()
  811. {
  812.   /* full reset */
  813.   int i;
  814.   ResetCalc();
  815.   entered=clrdisp=1;
  816.   lift_enabled = 0;
  817.   dnum=mem[0]=0.0;
  818.   if (rpn)
  819.       for (i=1; i < XCALC_MEMORY; i++)
  820.       mem[i]=0.0;
  821.   accset=exponent=Dpoint=0;
  822.   DrawDisplay();
  823. }
  824.  
  825.  
  826. #define STACKMAX 32
  827. static int opstack[STACKMAX];
  828. static int opsp;
  829. static double numstack[STACKMAX];
  830. static int numsp;
  831.  
  832.  
  833. /*******/
  834. PushOp(op)
  835.    int op;
  836. /*******/
  837. {
  838.   if (opsp==STACKMAX) {strcpy(dispstr,"stack error");  entered=3;}
  839.   else opstack[opsp++]=op;
  840. }
  841.  
  842. /*******/
  843. int PopOp()
  844. /*******/
  845. {
  846.   if (opsp==0) {
  847.       strcpy(dispstr,"stack error");
  848.       entered=3;
  849.       return(kNOP);
  850.   } else
  851.     return(opstack[--opsp]);
  852. }
  853.  
  854. /*******/
  855. int isopempty()
  856. /*******/
  857. {
  858.   return( opsp ? 0 : 1 );
  859. }
  860.  
  861. #ifdef DEBUG
  862. showstack(string)
  863.     char    *string;
  864. {
  865.     fprintf(stderr, "%s: %lf %lf %lf\n", string, numstack[0], numstack[1],
  866.         numstack[2]);
  867. }
  868. #endif
  869.  
  870. /*******/
  871. PushNum(num)
  872.  double num;
  873. /*******/
  874. {
  875.   if (rpn) {
  876.       numstack[2] = numstack[1];
  877.       numstack[1] = numstack[0];
  878.       numstack[0] = num;
  879.       return;
  880.   }
  881.   if (numsp==STACKMAX) {
  882.       strcpy(dispstr,"stack error");
  883.       entered=3;
  884.   } else
  885.     numstack[numsp++]=num;
  886. }
  887.  
  888. /*******/
  889. double PopNum()
  890. /*******/
  891. {
  892.     if (rpn) {
  893.     double tmp = numstack[0];
  894.     numstack[0] = numstack[1];
  895.     numstack[1] = numstack[2];
  896.     return(tmp);
  897.     }
  898.     if (numsp==0) {
  899.     strcpy(dispstr,"stack error");
  900.     entered=3;
  901.     return 0.0;
  902.     } else
  903.       return(numstack[--numsp]);
  904. }
  905.  
  906. /*******/
  907. RollNum(dir)
  908. /*******/
  909. {
  910.     double tmp;
  911.  
  912.     if (dir) {                /* roll up */
  913.     tmp         = dnum;
  914.     dnum        = numstack[2];
  915.     numstack[2] = numstack[1];
  916.     numstack[1] = numstack[0];
  917.     numstack[0] = tmp;
  918.     } else {                /* roll down */
  919.     tmp         = dnum;
  920.     dnum        = numstack[0];
  921.     numstack[0] = numstack[1];
  922.     numstack[1] = numstack[2];
  923.     numstack[2] = tmp;
  924.     }
  925. }
  926.  
  927.  
  928. /*******/
  929. ClearStacks()
  930. /*******/
  931. {
  932.     if (rpn)
  933.       numstack[0] = numstack[1] = numstack[2] = 0.;
  934.     opsp=numsp=0;
  935. }
  936.  
  937.  
  938. /*******/
  939. int priority(op)
  940.          int op;
  941. /*******/
  942. {
  943.     switch (op) {
  944.         case kPOW: return(2);
  945.         case kMUL:
  946.         case kDIV: return(1);
  947.         case kADD:
  948.         case kSUB: return(0);
  949.         }
  950.     return 0;
  951. }
  952.  
  953.  
  954. /********/
  955. ResetCalc()
  956. /********/
  957. {
  958.     flagM=flagINV=flagPAREN=0;  drgmode=DEG;
  959.     setflag(XCalc_MEMORY, False);
  960.     setflag(XCalc_INVERSE, False);
  961.     setflag(XCalc_PAREN, False);
  962.     setflag(XCalc_RADIAN, False);
  963.     setflag(XCalc_GRADAM, False);
  964.     setflag(XCalc_DEGREE, True);
  965.     strcpy(dispstr,"0");
  966.     draw(dispstr);
  967.     ClearStacks();
  968.     drg2rad=PI/180.0;
  969.     rad2drg=180.0/PI;
  970. }
  971.